function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }

function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }

function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }

function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }

function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }

function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }

function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

import { Graph, Shape } from '@antv/x6';
import { message } from 'antd';
import { getLabelText, autoSaveJson } from '../../tools';
const minimumLaneHeight = 50;
export function registerLane(config = {}) {
  const _config$width = config.width,
        width = _config$width === void 0 ? 500 : _config$width,
        _config$height = config.height,
        height = _config$height === void 0 ? 200 : _config$height;
  Graph.registerNode('lane', {
    width,
    height,
    inherit: 'rect',
    markup: [{
      tagName: 'rect',
      selector: 'body',
      className: 'laneBody'
    }, {
      tagName: 'rect',
      selector: 'nameRect',
      className: 'laneRect'
    }, {
      tagName: 'text',
      selector: 'nameText',
      className: 'laneName'
    }, {
      tagName: 'rect',
      selector: 'bottomBorder',
      className: 'resizeBorder'
    }],
    attrs: {
      body: {
        fill: 'transparent',
        stroke: '#f00',
        strokeWidth: 0,
        cursor: 'default'
      },
      nameRect: {
        width: 30,
        refHeight: '100%',
        fill: '#EAFEEC',
        stroke: '#fff',
        strokeWidth: 0,
        x: 0,
        cursor: 'default'
      },
      nameText: {
        ref: 'nameRect',
        textAnchor: 'middle',
        fontWeight: 'bold',
        fill: '#6A8E67',
        fontSize: 12,
        cursor: 'default'
      },
      bottomBorder: {
        refWidth: '100%',
        height: 2,
        stroke: '#9BD787',
        refY: '100%',
        refX: 0,
        y: -3,
        cursor: 'row-resize'
      }
    }
  }, true);
}
export function registerNode(config = {}) {
  const _config$width2 = config.width,
        width = _config$width2 === void 0 ? 120 : _config$width2,
        _config$height2 = config.height,
        height = _config$height2 === void 0 ? 100 : _config$height2; // #region 初始化图形

  const ports = {
    groups: {
      top: {
        position: 'top',
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: '#5F95FF',
            strokeWidth: 1,
            fill: '#fff',
            style: {
              visibility: 'hidden'
            }
          }
        }
      },
      right: {
        position: 'right',
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: '#5F95FF',
            strokeWidth: 1,
            fill: '#fff',
            style: {
              visibility: 'hidden'
            }
          }
        }
      },
      bottom: {
        position: 'bottom',
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: '#5F95FF',
            strokeWidth: 1,
            fill: '#fff',
            style: {
              visibility: 'hidden'
            }
          }
        }
      },
      left: {
        position: 'left',
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: '#5F95FF',
            strokeWidth: 1,
            fill: '#fff',
            style: {
              visibility: 'hidden'
            }
          }
        }
      }
    },
    items: [{
      group: 'top'
    }, {
      group: 'right'
    }, {
      group: 'bottom'
    }, {
      group: 'left'
    }]
  };
  Graph.registerNode('lane-node', {
    inherit: 'rect',
    width,
    height,
    markup: [{
      tagName: 'rect',
      selector: 'body'
    }, {
      tagName: 'text',
      selector: 'text'
    }, {
      tagName: 'image',
      selector: 'backgorund',
      className: 'mainImage'
    }, {
      tagName: 'image',
      selector: 'itemTag'
    }],
    attrs: {
      body: {
        strokeWidth: 0,
        // stroke: 'transparent',
        fill: 'transparent'
      },
      text: {
        fontSize: 10,
        fill: '#262626',
        refY: '80%'
      },
      backgorund: {
        refX: '10%',
        refY: '10%',
        refWidth: '80%',
        refHeight: '50%',
        opacity: 1
      },
      itemTag: {
        ref: 'backgorund',
        refX: '35%',
        refY: '15%',
        refWidth: '30%',
        refHeight: '30%',
        opacity: 1
      }
    },
    ports: _objectSpread({}, ports)
  }, true);
}
export function registerModuleNode() {
  Graph.registerNode('moduleNode', {
    inherit: 'rect',
    width: 190,
    height: 32,
    markup: [{
      tagName: 'rect',
      selector: 'body'
    }, {
      tagName: 'text',
      selector: 'text'
    }, {
      tagName: 'image',
      selector: 'icon'
    }],
    attrs: {
      body: {
        strokeWidth: 0,
        stroke: '#5F95FF',
        fill: '#fff'
      },
      icon: {
        ref: 'body',
        refX: 10,
        refY: 8,
        width: 16,
        height: 16
      },
      text: {
        refX: 36,
        refY: 17,
        fontSize: 12,
        fill: '#333',
        textAnchor: 'start'
      }
    }
  }, true);
}
export function registerEdge() {
  Graph.registerEdge('lane-edge', {
    inherit: 'edge',
    attrs: {
      line: {
        stroke: '#A2B1C3',
        strokeWidth: 2
      }
    },
    label: {
      attrs: {
        label: {
          fill: '#A2B1C3',
          fontSize: 12
        }
      }
    }
  }, true);
} // 控制连接桩显示/隐藏

const showPorts = (ports, show) => {
  for (let i = 0, len = ports.length; i < len; i = i + 1) {
    ports[i].style.visibility = show ? 'visible' : 'hidden';
  }
}; // 注册泳道的拖拽改变尺寸


export function registerResizeLane(graph, onLaneResize) {
  let dragNode = undefined;
  let offsetY = undefined;
  let oHeight = undefined;
  let minHeight = minimumLaneHeight;
  graph.on('node:mousedown', ({
    e,
    x,
    y,
    cell,
    node
  }) => {
    const target = e.target;

    if (target && target.className.baseVal === 'resizeBorder') {
      dragNode = cell;
      offsetY = y;
      oHeight = node.size().height;
      const children = node.getChildren();

      if (Array.isArray(children) && children.length) {
        minHeight = Math.max(...children.map(child => child.size().height));
      }
    }
  });
  graph.on('node:mousemove', ({
    y,
    node
  }) => {
    if (!dragNode) return;

    const _node$size = node.size(),
          width = _node$size.width;

    const height = (oHeight || 0) + y - (offsetY || 0);
    onLaneResize && onLaneResize(dragNode, width, height, minHeight);
  });
  graph.on('node:mouseup', () => {
    dragNode = undefined;
    offsetY = undefined;
    oHeight = undefined;
    minHeight = minimumLaneHeight;
  });
} // 注册节点尺寸改变和节点连线点显示的事件

export function registerResizeNode(graph) {
  graph.on('node:mouseenter', ({
    node
  }) => {
    if (node.shape !== 'lane-node') return;
    const container = graph.container;
    const ports = container.querySelectorAll('.x6-port-body');
    showPorts(ports, true);
  });
  graph.on('node:mouseleave', ({
    node
  }) => {
    if (node.shape !== 'lane-node') return;
    const container = graph.container;
    const ports = container.querySelectorAll('.x6-port-body');
    showPorts(ports, false);
  });
  graph.on('node:resizing', ({
    e,
    node,
    cell,
    view
  }) => {
    const target = e.target;

    if (target) {
      const _view$find = view.find('backgorund'),
            _view$find2 = _slicedToArray(_view$find, 1),
            mainImage = _view$find2[0];

      const width = Number(mainImage.getAttribute('width') || 0);
      const name = node.data.name;
      cell.attr({
        text: {
          text: getLabelText({
            label: name,
            placehoder: '...',
            maxTextLen: Math.floor(width / 6),
            maxLine: 2
          })
        }
      });
    }
  });
}
export function registerNodeMenuContext(graph, menuRef, callback) {
  graph.on('node:contextmenu', ({
    e,
    x,
    y,
    cell
  }) => {
    if (cell.data.type === 'lane') return;
    const menuContainer = menuRef.current;
    const clientWidth = menuContainer.clientWidth,
          clientHeight = menuContainer.clientHeight;
    menuContainer.style.left = `${x - clientWidth / 2}px`;
    menuContainer.style.top = `${y - clientHeight / 2}px`;
    callback && callback(cell);
  });
}
export function registerAutoSave(graph, callback) {
  graph.on('cell:added', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
    return regeneratorRuntime.wrap(function _callee$(_context) {
      while (1) switch (_context.prev = _context.next) {
        case 0:
          _context.next = 2;
          return autoSaveJson(null, graph);

        case 2:
        case "end":
          return _context.stop();
      }
    }, _callee);
  })));
  graph.on('cell:removed', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
    return regeneratorRuntime.wrap(function _callee2$(_context2) {
      while (1) switch (_context2.prev = _context2.next) {
        case 0:
          _context2.next = 2;
          return autoSaveJson(null, graph);

        case 2:
        case "end":
          return _context2.stop();
      }
    }, _callee2);
  })));
  graph.on('cell:changed', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {
    return regeneratorRuntime.wrap(function _callee3$(_context3) {
      while (1) switch (_context3.prev = _context3.next) {
        case 0:
          _context3.next = 2;
          return autoSaveJson(null, graph);

        case 2:
        case "end":
          return _context3.stop();
      }
    }, _callee3);
  })));
}
export function registerEdgeRemove(graph, callback) {
  graph.on('edge:mouseenter', ({
    edge
  }) => {
    edge.addTools([{
      name: 'button-remove',
      args: {
        distance: -40,

        onClick({
          view
        }) {
          const edge = view.cell;
          callback && callback(edge);
        }

      }
    }]);
  });
  graph.on('edge:mouseleave', ({
    edge
  }) => {
    edge.removeTools();
  });
} // 节点数量发生变化时

export function registerNodeNumChange(graph) {
  graph.on('node:added', ({
    node
  }) => {
    if (!node.parent) return;

    const _node$size2 = node.size(),
          nw = _node$size2.width;

    const gw = graph.container.clientWidth;
    const lane = graph.getCellById(node.parent.id);
    const nodes = lane.getChildren();
    const maxWidth = Math.max(gw, ...(nodes || []).map(n => n.position().x + n.size().width + nw + 100));

    if (maxWidth !== gw) {
      graph.getNodes().filter(n => n.shape === 'lane').forEach(laneNode => {
        const _laneNode$size = laneNode.size(),
              lh = _laneNode$size.height;

        laneNode.size(maxWidth, lh);
      });
      graph.container.style.width = maxWidth + 'px';
    }
  });
} // 监听history变化

export function registerHistory(graph, configs) {
  const setCanRedo = configs.setCanRedo,
        setCanUndo = configs.setCanUndo,
        onUndoOrRedo = configs.onUndoOrRedo; // 节点和边的添加和移除可能涉及到后端交互，因此这里交给开发者处理，组件不做处理

  graph.history.on('undo', args => {
    onUndoOrRedo && onUndoOrRedo('undo', graph, args);
  });
  graph.history.on('redo', args => {
    onUndoOrRedo && onUndoOrRedo('redo', graph, args);
  });
  graph.history.on('change', () => {
    setCanRedo(graph.history.canRedo());
    setCanUndo(graph.history.canUndo());
  });
}
export function registerLaneCellChange(cell, onLaneSizeChanged) {
  cell.on('change:size', () => onLaneSizeChanged());
}
export function registerKeyboard(graph, onActions) {
  // #region 快捷键与事件
  // copy
  graph.bindKey(['meta+c', 'ctrl+c'], () => {
    onActions && onActions('copy');
    return false;
  }); // paste

  graph.bindKey(['meta+v', 'ctrl+v'], () => {
    onActions && onActions('paste');
    return false;
  }); //undo

  graph.bindKey(['meta+z', 'ctrl+z'], () => {
    onActions && onActions('undo');
    return false;
  }); // redo

  graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => {
    onActions && onActions('redo');
    return false;
  }); //delete

  graph.bindKey('backspace', () => {
    onActions && onActions('delete');
  }); // zoom bigger

  graph.bindKey(['ctrl+1', 'meta+1'], () => {
    onActions && onActions('bigger');
  }); // zoom smaller

  graph.bindKey(['ctrl+2', 'meta+2'], () => {
    onActions && onActions('smaller');
  }); // clearStorage

  graph.bindKey(['ctrl+e', 'meta+e'], () => {
    onActions && onActions('clearStorage');
  });
}
export function getGraph(container, minimapContainer, config) {
  const _ref4 = config || {},
        onAddLink = _ref4.onAddLink;

  const graph = new Graph({
    panning: false,
    keyboard: true,
    history: {
      enabled: true,
      ignoreAdd: false,
      ignoreRemove: false,
      ignoreChange: false,

      beforeAddCommand(event, args) {
        const key = args.key,
              cell = args.cell;
        if (args.key === 'tools') return false; // 数据如果影响到节点样式会被记录到撤销队列，但是撤销的时候只能恢复样式，无法恢复数据
        // 因此禁止节点数据更新被记录到队列中

        if (event === 'cell:change:*' && cell.isNode() && key === 'attrs') {
          return false;
        }

        if (cell.isEdge()) {
          if (!cell.data) return false;
          const _cell$data = cell.data,
                source = _cell$data.source,
                target = _cell$data.target;
          if (!source || !target) return false;
        }

        return true;
      }

    },
    // minimap: {
    //   enabled: true,
    //   container: minimapContainer,
    //   width: minimapContainer.clientWidth,
    //   height: minimapContainer.clientHeight,
    //   // padding: 0,
    //   scalable: true,
    // },
    grid: {
      size: 10,
      visible: true,
      type: 'mesh'
    },
    container: container,
    selecting: {
      enabled: true,

      filter(node) {
        return node.shape !== 'lane';
      }

    },
    clipboard: true,
    resizing: {
      enabled: cell => {
        return cell.shape === 'lane-node';
      }
    },
    connecting: {
      allowNode: options => {
        const targetCell = options.targetCell;
        return targetCell.shape === 'lane-node';
      },
      router: 'manhattan',
      connector: {
        name: 'rounded',
        args: {
          radius: 8
        }
      },
      anchor: 'center',
      allowBlank: false,
      allowEdge: false,
      allowLoop: false,
      allowMulti: false,
      snap: {
        radius: 20
      },

      createEdge() {
        return new Shape.Edge({
          shape: 'lane-edge',
          attrs: {
            line: {
              stroke: '#A2B1C3',
              strokeWidth: 2
            }
          }
        });
      },

      validateEdge({
        edge
      }) {
        const sourceCell = edge.getSourceCell();
        const targetCell = edge.getTargetCell();

        if (!sourceCell || !targetCell || !sourceCell.parent || !targetCell.parent) {
          return false;
        }

        const sourceParentSort = sourceCell.parent.data.sort;
        const targetParentSort = targetCell.parent.data.sort; // 只能相邻层级节点进行连线

        if (Math.abs(sourceParentSort - targetParentSort) !== 1) {
          message.info({
            title: '提示',
            content: '只能对相邻的层级进行连线'
          });
          return false;
        }

        edge.data = {
          id: `${sourceCell.id}_${targetCell.id}`
        };
        onAddLink && onAddLink(edge);
        return false;
      }

    },
    translating: {
      restrict(cellView) {
        const cell = cellView.cell;
        const parentId = cell.prop('parent');

        if (parentId) {
          const parentNode = graph.getCellById(parentId);

          if (parentNode) {
            return parentNode.getBBox().moveAndExpand({
              x: 32,
              y: 0,
              width: -32,
              height: -4
            });
          }
        }

        return cell.getBBox();
      }

    }
  });
  return graph;
}